package de.axone.wash;

import java.util.Set;

import org.json.JSONException;
import org.json.JSONObject;


public interface Wash {
	
	public static enum Type{ STRING, INTEGER, FLOAT, BOOLEAN, DATA; };
	
	/*
	public static enum Charset{ 
		UTF8( "utf-8" ), LATIN1( "iso-8859-1" ); 
		
		private String code;
		public String code() { return code; }
		Charset( String code ){ this.code = code; }
	};
	*/
	
	public static class WashException extends Exception{
		public WashException(){ super(); }
		public WashException( String message ) { super( message ); } 
		public WashException( String message, Throwable cause ) { super( message, cause ); } 
		public WashException( Throwable cause ) { super( cause ); } 
	}
	public static class InitException extends WashException{ 
		public InitException( String message ) { super( message ); } 
		public InitException( String message, Throwable cause ) { super( message, cause ); } 
		public InitException( Throwable cause ) { super( cause ); } 
	}
	public static class NotFoundException extends WashException{

		private static final long serialVersionUID = -6602288480410968501L;}
	public static class WrongTypeException extends WashException{}
	public static class DuplicateEntryException extends WashException{}
	public static class CodingException extends WashException{ 
		public CodingException( String message ) { super( message ); } 
		public CodingException( String message, Throwable cause ) { super( message, cause ); } 
		public CodingException( Throwable cause ) { super( cause ); } 
	}
	
	
	// Creation ------------------------------------------------------
	
	/**
	 * Add one Field to this object
	 * 
	 * @param The name of the Field. 
	 * Names are created like java classes with dots separating
	 * @param The type of the Field
	 * 
	 * @throws WrongTypeException if the given Type doesn't match the value
	 * @trhows NotFoundException if there is no field of that name
	 */
	public void addField( String name, Type type ) throws DuplicateEntryException;
	
	/**
	 * Add one Field to this object and assing it a value
	 * 
	 * @param The name of the Field. 
	 * Names are created like java classes with dots separating
	 * @param The type of the Field
	 * @param The initial value
	 * 
	 * @throws DuplicateEntryException if this entry is already there
	 * @throws WrongTypeException if the given Type doesn't match the value
	 * @trhows NotFoundException if there is no field of that name
	 */
	public void addField( String name, Type type, Object value ) 
	throws DuplicateEntryException, WrongTypeException, NotFoundException;
	
	/**
	 * Remove Field from this object
	 * 
	 * @param name
	 * @throws NotFoundException
	 */
	public void removeField( String name ) throws NotFoundException;
	
	/**
	 * Returns if this field exists
	 * 
	 * @param The name of the field
	 * @return true if it exists, false otherwise
	 */
	public boolean hasField( String name );
	
	
	// GETTER/SETTER and Friends -------------------------------------
	
	/**
	 * Get a Set of field names
	 * 
	 * @return A Set of Strings of the field names
	 */
	public Set<String> getFieldNames();
	
	
	/**
	 * Return the type of a Field spezified by its name
	 * 
	 * @param Name of the Field
	 * 
	 * @return The Type
	 * 
	 * @trhows NotFoundException if there is no field of that name
	 */
	public Type getType( String name ) throws NotFoundException;
	
	
	/**
	 * Set the value of the field spezified by name
	 * 
	 * There are two things which can go wrong:
	 * <ol>
	 * <li>There is not field of that name. Then a NotFoundException is thrown</li>
	 * <li>There is a field but its not of the right Type. Then a WrongTypeException is thrown</li>
	 * </ol>
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 */
	public void set( String name, Object value ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Set the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public void setString( String name, String value ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Set the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public void setLong( String name, Long value ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Set the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public void setDouble( String name, Double value ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Set the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public void setBoolean( String name, Boolean value ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Set the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public void setData( String name, byte[] value ) throws NotFoundException, WrongTypeException;
	
	
	/**
	 * Get the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * 
	 * @see set()
	 */
	public Object get( String name ) throws NotFoundException;
	
	/**
	 * Get the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public String getString( String name ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Get the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public Long getLong( String name ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Get the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public Double getDouble( String name ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Get the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public Boolean getBoolean( String name ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Get the value of the field spezified by name
	 * 
	 * @param Name of the field
	 * @param The value to set this field to
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public byte[] getData( String name ) throws NotFoundException, WrongTypeException;
	
	/**
	 * Get this Wash object as JSONObject
	 * 
	 * @throws NotFoundException if there is no field by that name
	 * @throws WrongTypeException it the field is not of the correct type
	 * 
	 * @see set()
	 */
	public JSONObject getJSON( ) throws NotFoundException, WrongTypeException, JSONException;
	
	// Serialization -------------------------------------------------
	
	/**
	 * Write this object to a stream of bytes to send it over the wire
	 * 
	 * Strings are encoded according to the given encoding if possible.
	 * If not possible (because the character is not available in that
	 * encoding) the character is left out
	 * 
	 * @param encoding
	 * @return
	 */
	public String serialize();
	
	/**
	 * Fill this object with the given data.
	 * 
	 * Strings are created using the passed encoding
	 * 
	 * @param data
	 * @param encoding
	 */
	public void deserialize( String data ) throws CodingException;
	
}